package test.serverframe.armc.server.manager.service.exec;

import com.alibaba.fastjson.JSON;
import com.microcore.entity.AssertCondition;
import com.microcore.service.AssertService;
import com.microcore.service.asserts.model.AssertResult;
import com.microcore.util.SpringContextUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import test.serverframe.armc.server.manager.dao.mapper.*;
import test.serverframe.armc.server.manager.domain.*;
import test.serverframe.armc.server.manager.service.ServerApiService;
import test.serverframe.armc.server.manager.service.exec.params.InterfaceExecutorParams;
import test.serverframe.armc.server.util.JsonUtil;

import java.util.Date;
import java.util.List;
import java.util.UUID;

/**
 * 接口执行器
 *
 * @author LiuChunfu
 * @date 2019.01.19
 */
public class InterfaceExecutor implements Runnable {

	private Logger logger = LoggerFactory.getLogger(InterfaceExecutor.class);

	private InterfaceExecutorParams params;

	/**
	 * 要调用的接口api数据服务
	 */
	private ServerApiService apiService = SpringContextUtils.getBean("serverApiService", ServerApiService.class);

	/**
	 * 接口参数服务
	 */
	private LinkParamMapper linkParamMapper = SpringContextUtils.getBean("linkParamMapper", LinkParamMapper.class);

	/**
	 * 任务关联接口服务
	 */
	private TaskEnterInterfaceMapper taskEnterInterfaceMapper = SpringContextUtils.getBean("taskEnterInterfaceMapper",
			TaskEnterInterfaceMapper.class);

	/**
	 * 调度记录表服务
	 */
	private InvokeRecordMapper invokeRecordMapper = SpringContextUtils.getBean("invokeRecordMapper",
			InvokeRecordMapper.class);

	/**
	 * 任务记录表服务
	 */
	private InvokeTaskRecordMapper taskRecordMapper = SpringContextUtils.getBean("invokeTaskRecordMapper",
			InvokeTaskRecordMapper.class);

	/**
	 * 接口记录表服务
	 */
	private InterfaceInvokingRecordMapper interfaceRecordMapper = SpringContextUtils
			.getBean("interfaceInvokingRecordMapper", InterfaceInvokingRecordMapper.class);

	/**
	 * 接口调用执行入口服务
	 */
	private ExecutorEnterService executorEnterService = SpringContextUtils
			.getBean("executorEnterService", ExecutorEnterService.class);
	
	public InterfaceExecutor(InterfaceExecutorParams params) {
		this.params = params;
	}

	@Override
	public void run() {
		String inQuery = null;
		String inBody = null;
		String inHeader = null;
		Object out = null;
		TaskEnterInterface tei = null;
		InterfaceInvokingRecord interfaceRecord = new InterfaceInvokingRecord();
		try {
			tei = taskEnterInterfaceMapper.selectTaskEnterInterId(params);
			// 初始化接口记录表
			interfaceRecord.setTaskRelateInterId(tei.getTaskEnterId());
			interfaceRecord.setStartTime(new Date());
			interfaceRecord.setInterfaceInvokingRecordId(UUID.randomUUID().toString());
			interfaceRecord.setInvokeTaskRecordId(params.getTaskRecordId());
			LinkParam interfaceParam = linkParamMapper.selectByInterRelateTaskId(tei.getTaskEnterId());
			inQuery = interfaceParam.getInQuery();
			inBody = interfaceParam.getInBody();
			inHeader = interfaceParam.getInHeader();
			if (StringUtils.isNotBlank(tei.getParentIds())) {
				// 当父节点不为空时，从父节点中替换当前节点的in参数值
				for (String nodeId : JSON.parseArray(tei.getParentIds(), String.class)) {
					// 从缓存里获取当前接口父类执行的出参作为自己的入参
					String outParam = params.getCache().get(nodeId);
					if (StringUtils.isNotBlank(outParam)) {
						inQuery = JsonUtil.convert(outParam, inQuery, nodeId);
						inBody = JsonUtil.convert(outParam, inBody, nodeId);
						inHeader = JsonUtil.convert(outParam, inHeader, nodeId);
					}
				}
			}
			logger.info("inQuery：" + inQuery);
			logger.info("inBody：" + inBody);
			logger.info("inHeader：" + inHeader);
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		try {
			out = apiService.getInterfaceResponse(tei.getInterfaceId(), inQuery, inBody, inHeader);
			logger.info("interface execute out value :" + out);
		} catch (Exception e) {
			out = e;
			interfaceRecord.setStatus(Constants.FAILED);
			logger.error("接口执行时，发生异常：" + e.getMessage());
			e.printStackTrace();
		} finally {
			boolean flag = handle(tei.getNodeId(), tei.getTaskEnterId(), interfaceRecord, out);
			interfaceRecordMapper.insertSelective(interfaceRecord);
			logger.info("interface record updated :" + interfaceRecord.toString());
			if (flag) {
				incrementSuccess();
				params.getInterfaceDagNode().putToDeath();
			} else {
				String failedStrategy = params.getFailedStrategy();
				switch (failedStrategy) {
				case Constants.FAILED_STRATEGY_CONTINUE:
					// 0：继续执行 每执行完一次接口将该接口putToDeath
					params.getInterfaceDagNode().putToDeath();
					break;
				case Constants.FAILED_STRATEGY_STOP:
					// 1：停止业务执行
					//interfaceRecord.setStatus(Constants.FAILED);
					break;
				default:
					// 2：重新执行 2,111: 2是重新执行，111是等待111s再执行
					try {
						// 重新执行一次
						if (!params.getIsReStart()) {
							// 等待一段时间
							String[] failed = failedStrategy.split(",");
							String timeStr = failed[1];
							logger.info("timeStr: " + timeStr);
							Thread.sleep(Integer.valueOf(timeStr) * 1000);
							executorEnterService.executorEnter(params.getTaskInvokeId(), String.valueOf(true));
						}
						
					} catch (Exception e) {
						e.printStackTrace();
					} 
					break;
				}

			}
			
			incrementExecuted();
			// 记录表更新
			updateRecord();
		}
	}

	/**
	 * 更新记录表
	 */
	private synchronized void updateRecord() {
		Date end = new Date();
		// int i = params.getInterfaceTotal().incrementAndGet();
		if (params.getExpectedInterfaceTotal() == params.getInterfaceTotal().get()) {
			// 接口执行数与预期接口执行数一致
			// 更新任务记录表
			InvokeTaskRecord taskRecord = new InvokeTaskRecord();
			taskRecord.setInvokeRecordId(params.getInvokeRecordId());
			taskRecord.setInvokeTaskRecordId(params.getTaskRecordId());
			taskRecord.setEndTime(end);
			taskRecord.setInterfaceSuccessTotal(String.valueOf(params.getSuccessInterfaceTotal().get()));
			taskRecord.setStatus(isSuccess(params.getInterfaceTotal().get(), params.getSuccessInterfaceTotal().get()));
			taskRecordMapper.updateByPrimaryKeySelective(taskRecord);
			logger.info("task record updated :" + taskRecord.toString());
		}
		// int j = params.getTaskTotal().incrementAndGet();
		InvokeRecord invokeRecord = new InvokeRecord();
		invokeRecord.setRecordId(params.getInvokeRecordId());
		invokeRecord.setEndTime(end);
		invokeRecord.setTaskSuccessTotal(String.valueOf(params.getSuccessTaskTotal()));
		if (params.getExpectedTaskTotal() == params.getTaskTotal().get()) {
			// 任务执行数与预期任务执行数一致
			// 更新调度记录表
			invokeRecord.setStatus(isSuccess(params.getTaskTotal().get(), params.getSuccessTaskTotal().get()));
		} else {
			invokeRecord.setStatus(Constants.FAILED);
		}
		invokeRecordMapper.updateByPrimaryKeySelective(invokeRecord);
		logger.info("invoke record updated :" + invokeRecord.toString());
	}

	/**
	 * 是否成功
	 *
	 * @param total
	 * @param success
	 * @return
	 */
	public int isSuccess(int total, int success) {
		if (total != 0 && total == success) {
			return Constants.SUCCESS;
		}
		return Constants.FAILED;
	}

	private synchronized void incrementSuccess() {
		int i = params.getSuccessInterfaceTotal().incrementAndGet();
		if (params.getExpectedInterfaceTotal() == i) {
			// 当预期接口执行数与接口成功执行数相等时，任务执行成功数+1
			params.getSuccessTaskTotal().incrementAndGet();
		}
	}

	/**
	 * 执行
	 */
	private synchronized void incrementExecuted() {
		int i = params.getInterfaceTotal().incrementAndGet();
		if (params.getExpectedInterfaceTotal() == i) {
			// 当预期接口执行数与接口执行数相等时，任务执行数+1
			params.getTaskTotal().incrementAndGet();
			// 当前任务下的接口执行完了，将当前任务putToDeath，执行下一个任务
			params.getTaskDagNode().putToDeath();
		}
	}

	/**
	 * 断言的服务类
	 */
	private AssertService assertService = SpringContextUtils.getBean("assertService", AssertService.class);

	/**
	 * @param nodeId
	 *            节点ID
	 * @param fkId
	 *            外键ID
	 * @param record
	 *            记录表对象
	 * @param data
	 *            请求的响应结果
	 * @return
	 */
	public boolean handle(String nodeId, String fkId, InterfaceInvokingRecord record, Object data) {
		record.setEndTime(new Date());
		if (data instanceof String) {
			// 成功
			String resultJson = data.toString();
			List<AssertCondition> assertList = assertService.getAssert(fkId);
			for (AssertCondition assertCondition : assertList) {
				AssertResult assertResult = AssertService.toAssert(resultJson, assertCondition.getConditions());
				if (!assertResult.isSuccess()) {
					// 保存断言判断的错误信息
					record.setAssertValue(assertResult.toString());
					record.setStatus(Constants.FAILED);
					return false;
				}
			}
			record.setReturnValue(resultJson);
			record.setStatus(Constants.SUCCESS);
			// 请求成功并且断言判定无错误时，缓存请求结果
			params.getCache().put(nodeId, resultJson);
			return true;
		} else {
			// 异常的错误信息,放入返回值中
			record.setReturnValue(((Throwable) data).getMessage());
			record.setStatus(Constants.FAILED);
			return false;
		}
	}

}